﻿using EWSEditor.Forms;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using EWSEditor.Exchange;

namespace EWSEditor.CRM.Forms
{
    public partial class ExchangeSyncIdMappingForm : DialogForm
    {

        private ItemId _id;
        private EntityCollection _mappings;
        private int _objecttypecode;
        private ExchangeService _exchangeservice;

        public ExchangeSyncIdMappingForm(ItemId id, ExchangeService service)
        {
            InitializeComponent();
            _id = id;
            _exchangeservice = service;
            Thread preparedatathread = new Thread(new ThreadStart(SetupForm));
            preparedatathread.SetApartmentState(ApartmentState.STA);
            preparedatathread.Start();
        }
        //Second constructor to accept input to retrieve all mappings based on object type...
        public ExchangeSyncIdMappingForm(int ObjectTypeCode, ExchangeService service)
        {
            InitializeComponent();
            _objecttypecode = ObjectTypeCode;
            _exchangeservice = service;
            Thread preparedatathread = new Thread(new ThreadStart(SetupForm));
            preparedatathread.SetApartmentState(ApartmentState.STA);
            preparedatathread.Start();
        }

        private void SetupForm()
        {
            if (_id != null)
            {
                SetObjectTypeCode();
            }
            RetrieveMappings();
            if (_mappings.Entities.Count > 0)
            {
                SortableBindingList<ExchangeSyncIdMapping> mappinglist = new SortableBindingList<ExchangeSyncIdMapping>();
                foreach (Entity mapping in _mappings.Entities)
                {
                    ExchangeSyncIdMapping syncmapping = new ExchangeSyncIdMapping(mapping);
                    mappinglist.Add(syncmapping);
                }
                this.Invoke(new Action<SortableBindingList<ExchangeSyncIdMapping>>(SetDataSource), mappinglist);
            }
            else
            {
                this.Invoke(new Action(DisplayNoMappingsError));
            }
        }

        private void DisplayNoMappingsError()
        {
            btnViewInCRM.Enabled = false;
            btnViewInEWS.Enabled = false;
            btnViewInOWA.Enabled = false;
            MessageBox.Show("No ExchangeSyncIdMapping records were returned. The selected mapping may not exist or you may not have permissions to retrieve it.", "No mappings found");
        }

        private void SetObjectTypeCode()
        {
            Item item = Item.Bind(_exchangeservice, _id);
            if (item.ItemClass == "IPM.Contact") { _objecttypecode = 2; }
            if (item.ItemClass == "IPM.Appointment") { _objecttypecode = 4201; }
            if (item.ItemClass == "IPM.Task") { _objecttypecode = 4212; }
        }

        private void SetDataSource(SortableBindingList<ExchangeSyncIdMapping> mappinglist)
        {
            grdMapping.DataSource = mappinglist;
        }

        private void RetrieveMappings()
        {
            OrganizationServiceProxy orgProxy = CrmAuthInfoFactory.GetOrgProxy();
            QueryByAttribute query = new QueryByAttribute("exchangesyncidmapping");

            //We know the _id if the user used the right-click menu context.
            if (_id != null)
            {
                query.ColumnSet = new ColumnSet() { AllColumns = true };
                query.Attributes.AddRange("exchangeentryid");
                query.Values.AddRange(_id.ToString());
                query.Attributes.AddRange("ownerid");
                query.Values.AddRange(CrmOrgMailboxCache.LoggedInSystemUser.Id);
                _mappings = orgProxy.RetrieveMultiple(query);
                return;
            }

            //User used the mnuViewMappings, so get all.
            //If Task was selected, we need to retrieve all "task" types such as phone call, fax, etc.
            //In the future, we will need to expand this to include custom activities as well.
            if (_objecttypecode == 4212)
            {
                RetrieveMappingsWithQueryExpression(orgProxy);
                return;
            }
            query.ColumnSet = new ColumnSet() { AllColumns = true };
            query.Attributes.AddRange("objecttypecode");
            query.Values.AddRange(_objecttypecode);
            query.Attributes.AddRange("ownerid");
            query.Values.AddRange(CrmOrgMailboxCache.LoggedInSystemUser.Id);
            _mappings = orgProxy.RetrieveMultiple(query);
            return;
        }

        private void RetrieveMappingsWithQueryExpression(OrganizationServiceProxy orgProxy)
        {
            ConditionExpression taskcondition = new ConditionExpression();
            taskcondition.AttributeName = "objecttypecode";
            taskcondition.Operator = ConditionOperator.Equal;
            taskcondition.Values.Add(4212);

            ConditionExpression phonecallcondition = new ConditionExpression();
            phonecallcondition.AttributeName = "objecttypecode";
            phonecallcondition.Operator = ConditionOperator.Equal;
            phonecallcondition.Values.Add(4210);

            ConditionExpression lettercondition = new ConditionExpression();
            lettercondition.AttributeName = "objecttypecode";
            lettercondition.Operator = ConditionOperator.Equal;
            lettercondition.Values.Add(4207);

            ConditionExpression faxcondition = new ConditionExpression();
            faxcondition.AttributeName = "objecttypecode";
            faxcondition.Operator = ConditionOperator.Equal;
            faxcondition.Values.Add(4204);

            FilterExpression filter = new FilterExpression();
            filter.Conditions.Add(phonecallcondition);
            filter.Conditions.Add(phonecallcondition);
            filter.Conditions.Add(lettercondition);
            filter.Conditions.Add(faxcondition);
            filter.FilterOperator = Microsoft.Xrm.Sdk.Query.LogicalOperator.Or;

            QueryExpression query = new QueryExpression("exchangesyncidmapping");
            query.ColumnSet = new ColumnSet() { AllColumns = true };
            query.Criteria.AddFilter(filter);

            _mappings = orgProxy.RetrieveMultiple(query);

            return;
        }

        private void txtErrorCode_TextChanged(object sender, EventArgs e)
        {

        }

        private void grdMapping_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
           
        }

        private void grdMapping_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            foreach(DataGridViewRow row in grdMapping.SelectedRows)
            {
                row.Selected = false;
            }
        }

        private void btnViewInCRM_Click(object sender, EventArgs e)
        {
            SharedUtilities.OpenInCRM(_objecttypecode, ((ExchangeSyncIdMapping)grdMapping.CurrentRow.DataBoundItem).objectid.ToString());
        }

        private void grdMapping_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (grdMapping.CurrentRow == null)
            {
                return;
            }
            btnViewInCRM.Enabled = true;
            ExchangeSyncIdMapping mapping = (ExchangeSyncIdMapping)grdMapping.CurrentRow.DataBoundItem;

            if (mapping.mappingentity.Contains("lastsyncerror"))
            { txtbxLastError.Text = (string)mapping.mappingentity["lastsyncerror"]; }
            else { txtbxLastError.Text = ""; }

            if (mapping.mappingentity.Contains("lastsyncerroroccurredon"))
            { txtbxLastSyncErrorOccurredOn.Text = ((DateTime)mapping.mappingentity["lastsyncerroroccurredon"]).ToString(); }
            else { txtbxLastSyncErrorOccurredOn.Text = ""; }

            if (mapping.mappingentity.Contains("lastsyncerrorcode"))
            { txtErrorCode.Text = ((int)mapping.mappingentity["lastsyncerrorcode"]).ToString(); }
            else { txtErrorCode.Text = ""; }
        }

        private void ExchangeSyncIdMappingForm_KeyDown(object sender, KeyEventArgs e)
        {
            //Not needed
            
        }

        /// <summary>
        /// Suppress the KeyDown event on the grdMapping to prevent an issue with displaying the error detail.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void grdMapping_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Down || e.KeyData == Keys.Up || e.KeyData == Keys.Left || e.KeyData == Keys.Right)
            {
                e.Handled = true;
                e.SuppressKeyPress = true;
            }
        }

        private void btnViewInEWS_Click(object sender, EventArgs e)
        {
            List<ItemId> itemlist = new List<ItemId>();
            ItemId itemid = GetItemIdFromGrid();
            itemlist.Add(itemid);
            ItemsContentForm.Show("Viewing Item by ItemId", itemlist, _exchangeservice, this);
        }

        private void btnViewInOWA_Click(object sender, EventArgs e)
        {
            ItemId itemid = GetItemIdFromGrid();
            Item.Bind(_exchangeservice, itemid); //Binding to item to populate ServerInfo
            ItemsContentForm.OpenOWAFromWebClientReadFormQueryString(_exchangeservice, itemid);
        }

        private ItemId GetItemIdFromGrid()
        {
            string uniqueid = ((ExchangeSyncIdMapping)grdMapping.CurrentRow.DataBoundItem).exchangeentryid;
            ItemId itemid = new ItemId(uniqueid);
            return itemid;
        }
    }
}
